/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package MortgageCore;

import Household.Household;
import Bank.Bank;

/**
 *
 * @author karakots
 */
public class Mortgage implements iDebt, iGoverned {
    private boolean preApproved;
    private double preapprovedAmount;
    private boolean funded;
    private double fundedAmount;
    private double debtOwed;
    private MortgageTerms myTerms;
    private Bank bank;
    private Household household;
    private int daysValid;
    private int accountNumber;
    private int numPayments;
    private DebtState myState;
    private int numMissedPayments;
    private double amountToBorrow;


    public Mortgage(Bank b, Household hh, double amount, MortgageTerms terms, boolean preApp, int daysVal) {
        preApproved = preApp;
        preapprovedAmount = amount;
        bank = b;
        household = hh;
        funded = false;
        fundedAmount = 0;
        debtOwed = 0;
        myTerms = terms;
        daysValid = daysVal;
        accountNumber = -1;
        numPayments = 0;
        myState = DebtState.kDebtPreapproved;
        numMissedPayments = 0;
        amountToBorrow = 0;
    }

    public double getFundedAmount()             {return fundedAmount;}
    public double getPreapprovedAmount()        {return preapprovedAmount;}
    public double getAmountToBorrow()           {return amountToBorrow;}
    public void setAmountToBorrow(double d)     {amountToBorrow = d;}
    public void setPreapproved(boolean p)       {preApproved = p;}
    public boolean getPreapproved()             {return preApproved;}
    public void setFunded(boolean p)            {funded = p;}
    public void setDaysValid(int days)          {daysValid = days;}
    public MortgageTerms getTerms()             {return myTerms;}
    public double getPctPaid()                  {return 1 - (debtOwed/fundedAmount);}
    public boolean getPaidInFull()              {return myState == DebtState.kDebtPaidInFull;}
    public int getNumPayments()                 {return numPayments;}
    public boolean isFunded()                   {return funded;}
    public void setBank(Bank b)                 {bank = b;}
    public Bank getBank()                       {return bank;}
    public double getDebtOwed()                 {return debtOwed;}
    public int getNumMissedPayments()           {return numMissedPayments;}

    public void simInit(double loanAmount) {
        setFunded(true);
        fundedAmount = loanAmount;
        debtOwed = loanAmount;
        myState = DebtState.kDebtFunded;
    }

    public boolean ageMortgage() {
        // return false only if mortgage expires
        boolean mortgageValid;
        // we need to set it prevent mortgage from expiring when a funding is pending
        if (!(myState == DebtState.kDebtFunded) && !funded) {
        //if (!funded) {
            if (daysValid > 0) {
                daysValid--;
            }
            if (daysValid > 0)
               mortgageValid = true;
            else {
                mortgageValid = false;
                myState = DebtState.kDebtOfferExpired;
            }
            //return (daysValid > 0);
        } else
            mortgageValid = true;
            //return true;
        return mortgageValid;
    }

    public void borrowerMortgageExpired() {
        household.preAppMortgageExpired(this);
    }


    //
    // iDebt Interface
    //

    // lender gives cash to borrower; debt instrument tracks this
    public void hereIsFunding(double amount) {
        if (amount > 0) {
            funded = true;
            fundedAmount = amount;
            debtOwed = amount;
            // tell borower loan is funded
            household.action(household.mortgageFunded(this));
        } else {
            // tell borrower loan can not be funded
            // we can send the expired message-- it will have the desired effect on the household
            household.preAppMortgageExpired(this);
        }
    }
    public void becomeFunded() {
        // ask bank to fund mortgage
        if (preApproved && (bank != null)) {
            bank.action(bank.requestFunding(this, amountToBorrow));
            myState = DebtState.kDebtFunded;
        }
    }
    public double requestPaymentAmount() {
        return getMonthlyPayment();
    }

    public double getMonthlyPayment() {
        double payment = bank.getMonthlyPayment(myTerms.getMonthlyInterestRate(), myTerms.getLengthInYears() * 12, fundedAmount);
        return payment;
    }

    public void  borrowerCancel() {
        bank.cancelMortgage(this);
    }

   public void makePayment(double amount) {
        boolean paidOff = false;
        double principalPaid;
        if (amount == debtOwed) {
            debtOwed = 0;   // takes care of roundoff errors
            paidOff = true;
            principalPaid = amount;
        } else {
            double i = myTerms.getMonthlyInterestRate();
            double n = (myTerms.getLengthInYears() * 12);
            principalPaid = amount - (debtOwed * i);
            debtOwed -= principalPaid;
            if (debtOwed < 0) {
                if (debtOwed < -0.01) {
                    boolean wawaoo = true;
                }
                if (numPayments < (n-1)) {
                    boolean wawaoo = true;
                }
            }

            if (++numPayments == n) {
                debtOwed = 0;   // takes care of roundoff errors
                paidOff = true;
            }
        }
        // send paymant to the bank
        bank.payment(amount, principalPaid);
        // if the loan is paid off, let evreyone know
        if (paidOff) {
            
            // let bank update books
            bank.paidInFull();
            
            // remove mortgage from bank
              bank.cancelMortgage(this);
            // the household should set this mortgage to null
            household.mortgagePaidInFull(this);
            // I'll be going away soon!
            myState = DebtState.kDebtPaidInFull;
        }
    }

    public void payPoints(double amount) {
       bank.payPoints(amount);
    }

    public void defaultOnMortgage() {
        myState = DebtState.kDebtInDefault;
    }

    public void missedPayment() {
        myState = DebtState.kDebtInDefault;

        // if first time then inform bank to update books
        if (numMissedPayments == 0) {
           bank.missedPayment();
        }
        
        numMissedPayments++;
    }

    public void cancelDebt(iLender lender) {

    }

    // iGoverned Interface
    public void updateRegsAndExternals(Regulations regs, Externals ext) {

    }
}
